/*=========================================================================
 Copyright (c) 2008, Nokia Corporation and/or its subsidiary(-ies).
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
 
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
     * Neither the name of the Nokia Corporation and/or its subsidiary(-ies)nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================================*/

#ifndef NCVMATRIX_H
#define NCVMATRIX_H

#include "ncvFixed.h"	
#include <e32std.h>
#include <e32math.h>

/*! \enum TNorm
 *  \brief Enum type of possible norms
 */
enum TNorm
	{
	ENormInf,
	ENorm2,
	ENorm1,
	ENormF
	};

/**
 * \class CNokiaCVMatrix
 * \brief Fixed point matrix representation.
 * A standard matrix is initialized as a zero matrix. 
 * Special cases are Eye (Identity matrix) and Ones (all ones).
 * Usage:
 * <pre>
 * CNokiaCVMatrix* m = CNokiaCVMatrix->NewL(5,5);
 * CleanupStack::PushL(m);
 * (*m)(3,3) = 2;
 * (*m)(2,3) = 4.23;
 * CNokiaCVMatrix* n = CNokiaCVMatrix->Ones(5,5);
 * CleanupStack::PushL(n);
 * CNokiaCVMatrix *res = (*m)*(*n)*5;
 * CleanupStack::PushL(res);
 * CFixed det = res->Det();
 * ...
 * CleanupStack::Pop(m);
 * CleanupStack::Pop(n);
 * CleanupStack::Pop(res);
 * delete m;
 * delete n;
 * delete res;
 * </pre>
 */
class CNokiaCVMatrix : public CBase
	{
public:

	IMPORT_C virtual ~CNokiaCVMatrix();
	
protected:
	CNokiaCVMatrix();
	
	/*!
	 * \brief The actual constructor for NewL(const TInt aRows, const TInt aCols)
	 *		  and the corresponding special cases
	 * \param aRows - the number of rows in the matrix
	 * \param aCols - the number of columns in the matrix
	 * \return A pointer to the created matrix
	 * \note the function can leave
	 */
	void ConstructL(const TInt aRows, const TInt aCols);
	
	/*!
	 * \brief The actual constructor for NewL(const CNokiaCVMatrix &aMatrix) and the corresponding special cases
	 * \param aRows - the number of rows in the matrix
	 * \param aCols - the number of columns in the matrix
	 * \return A pointer to the created matrix
	 * \note the function can leave
	 */
	void ConstructL(const CNokiaCVMatrix &aMatrix);
	
	/*!
	 * \brief The actual constructor for NewL(const CFixed** array) and the corresponding special cases
	 * \param aRows - the number of rows in the matrix
	 * \param aCols - the number of columns in the matrix
	 * \return A pointer to the created matrix
	 * \note the function can leave
	 */
	void ConstructL(const CFixed** array);
	/*!
	 * \brief The actual constructor for NewL(const TInt aRows, const TInt aCols, const CFixed** array) and the corresponding special cases
	 * \param aRows - the number of rows in the matrix
	 * \param aCols - the number of columns in the matrix
	 * \return A pointer to the created matrix
	 * \note the function can leave
	 */	
	void ConstructL(const TInt aRows, const TInt aCols, const CFixed **array);		
	
public:

	/*!
	 * \brief Creates a new matrix according to the given array
	 * \param array - the array from which the matrix is constructed
	 * \return A pointer to the created array
	 * \note the function can leave
	 */
	IMPORT_C static CNokiaCVMatrix* NewL(const CFixed** array);
	/*!
	 * \brief Creates a new matrix according to the given array
	 * \param array - the array from which the matrix is constructed
	 * \return A pointer to the created array
	 * \note the function can leave
	 */
	IMPORT_C static CNokiaCVMatrix* NewL(const TInt aRows, const TInt aCols, const CFixed** array);
	
	/*!
	 * \brief Creates a new matrix according to size given with initial value zero
	 * \param aRows - the number of rows in the matrix
	 * \param aCols - the number of columns in the matrix
	 * \return A pointer to the created matrix
	 * \note the function can leave
	 */
	IMPORT_C static CNokiaCVMatrix* NewL( const TInt aRows, const TInt aCols );
	
	/*!
	 * \brief Creates a new matrix according to the given matrix
	 * \param aMatrix - the matrix from which the matrix is constructed (cloned)
	 * \return A pointer to the created matrix
	 * \note the function can leave
	 */
	IMPORT_C static CNokiaCVMatrix* NewL( const CNokiaCVMatrix &aMatrix);
	
	/*!
	 * \brief Same as NewL
	 * \return A pointer to the created matrix
	 * \note the function can leave
	 */
	IMPORT_C static CNokiaCVMatrix* Zeros(  const TInt aRows, const TInt aCols );
	
	/*!
	 * \brief  Constructs a new matrix having ones on its diagonal, if aCols == aRows
	 *  	   constructs an Identity matrix
	 * \param aRows - the number of rows in the matrix
	 * \param aCols - the number of columns in the matrix
	 * \return A pointer to the created matrix
	 * \note the function can leave
	 */
	IMPORT_C static CNokiaCVMatrix* Eye(  const TInt aRows, const TInt aCols );
	
	/*!
	 * \brief Creates a new matrix according to size given with initial value of each
	 *        element is one
	 * \param aRows - the number of rows in the matrix
	 * \param aCols - the number of columns in the matrix
	 * \return A pointer to the created matrix
	 * \note the function can leave
	 */
	IMPORT_C static CNokiaCVMatrix* Ones(  const TInt aRows, const TInt aCols );
	
	/*!
	 * \brief Getter for the columnsize of the matrix
	 * \return iCols - the number of columns in this matrix
	 */
	IMPORT_C TInt Cols();
	
	/*!
	 * \brief Getter for the rowsize of the matrix
	 * \return iRows - the number of rows in this matrix
	 */
	IMPORT_C TInt Rows();
	
	/** @name Operations
	 *  Matrix operations. Every operation throws an KErrArgument error,
	 *  if the operation is not allowed for the given matrices e.g. when columnsize
	 *  dose not match.
	 */
	//@{
	
	/*!
	 * \brief Getter and setter for the element at the give index
	 * \param aRow - the row number (starting from zero) from where to set/get an element
	 * \param aCol - the columns number (starting from zero) from where to set/get an element
	 * \return the corresponding element in the matrix
	 */
	IMPORT_C CFixed& operator()(const TInt aRow, const TInt aCol);
	
	IMPORT_C CNokiaCVMatrix& operator =(const CNokiaCVMatrix& aMatrix);
	IMPORT_C TBool operator ==(const CNokiaCVMatrix& aMatrix);
	IMPORT_C TBool operator !=(const CNokiaCVMatrix& aMatrix);
	
	IMPORT_C CNokiaCVMatrix* operator +(const CNokiaCVMatrix& aMatrix);
	IMPORT_C CNokiaCVMatrix& operator +=(const CNokiaCVMatrix& aMatrix);
	
	IMPORT_C CNokiaCVMatrix* operator -(const CNokiaCVMatrix& aMatrix);
	IMPORT_C CNokiaCVMatrix& operator -=(const CNokiaCVMatrix& aMatrix);
	
	IMPORT_C CNokiaCVMatrix* operator*(const CNokiaCVMatrix& aMatrix);
	IMPORT_C CNokiaCVMatrix& operator *=(const CNokiaCVMatrix& aMatrix);
	
	IMPORT_C CNokiaCVMatrix* operator*(const CFixed aScalar);
	IMPORT_C CNokiaCVMatrix& operator*=(const CFixed aScalar);
	
	IMPORT_C CNokiaCVMatrix* operator /(const CNokiaCVMatrix& aMatrix);
	IMPORT_C CNokiaCVMatrix& operator /=(const CNokiaCVMatrix& aMatrix);
	
	IMPORT_C CNokiaCVMatrix* operator /(const CFixed aScalar);
	IMPORT_C CNokiaCVMatrix& operator /=(const CFixed aScalar);
	//@}
	
	
	/** @name Matrix Norms
	 *
	 */
	//@{
	/*!
	* \brief Calculates the norm of this matrix of the given type
	* \param aNormType - the type of the norm, see TNorm for more information
	* \return the value of the norm. 
	* \note An exception is thrown in Norm2() if it fails to find the singular values of this matrix
	* \note the function can leave
	*/
	IMPORT_C CFixed Norm(TNorm aNormType);
	
	/*!
	 * \brief Calculates the Frobenius norm of this matrix
	 * \note the function can leave
	 */
	IMPORT_C CFixed NormF();
	/*!
	 * \brief Calculates the infinity norm of this matrix
	 */
	IMPORT_C CFixed NormInf();
	/*!
	 * \brief Calculates the number one norm of this matrix
	 */
	IMPORT_C CFixed Norm();
	/*!
	 * \brief Calculates the number two norm of this matrix
	 * \note Exception is thrown if SVD fails
	 * \note the function can leave
	 */
	IMPORT_C CFixed Norm2();
	//@}
	
	/*!
	 * \brief Calculates the inverse matrix of this matrix
	 * \note KErrArgument is thrown if inversion not allowed
	 * \return the inverse matrix
	 * \note the function can leave
	 */
	IMPORT_C CNokiaCVMatrix* Inverse() const;
	/*!
	 * \brief Calculates the transpose matrix of this matrix
	 * \return the inverse matrix
	 * \note the function can leave
	 */
	IMPORT_C CNokiaCVMatrix* Transpose() const;
	
	/*!
	 * \brief Calculates the eigenvalues of this matrix
	 * \return the eigenvalues in a 2xCols table, where the
	 *         real part of the eigenvalue is stored in the 0 row
	 *         and the corresponding imaginary part in the number 1 row
	 *
	 *  \note An exception is thrown, if the eigenvalue decomposition fails e.g. because
	 *  the given matrix isn't square
	 * \note the function can leave
	 */
	IMPORT_C CFixed** Eigenvalues();
	
	/*!
	 * \brief Calculates the singular values of this matrix using ncvSVD
	 * \return the singular values in a corresponding table
	 *
	 * \note An excption is thorwn, if the svd fails
	 * \see CSVD for more details
	 * \note the function can leave
	 */
	IMPORT_C CFixed* Singularvalues();
	
	/*!
	 * \brief Calculates the determinant of this matrix
	 * \return the determinant of this matrix, or zero if it can't be calculated
	 *
	 */
	IMPORT_C CFixed Det() const; 
	
	/*!
	 * \brief Checks if this matrix is a square matrix
	 * \return ETrue if square, false otherwise
	 *
	 */
	IMPORT_C TBool IsSquare() const; //Easy to check are some operators/operations allowed
	/*!
	 * \brief Checks if this matrix is singular
	 * \return ETrue if singular, false otherwise
	 *
	 */
	IMPORT_C TBool IsSingular() const;
	/*!
	 * \brief Checks if this matrix is s symmetric
	 * \return ETrue if symmetric, false otherwise
	 *
	 */
	IMPORT_C TBool IsSymmetric() const;
	
	/*!
	 * \brief Helper method calculates hypotenuse between two points
	 * \return The hypotenuse between two points
	 *
	 */
	IMPORT_C static CFixed Pythag(CFixed a, CFixed b);
	
	/*!
	 * \brief Partial pivoting method
	 * \param aRow - the row to pivot
	 * \param aMatrix - the matrix to pivot
	 * \return The index of the pivot element
	 */
	IMPORT_C TInt Pivot(TInt aRow, CNokiaCVMatrix *aMatrix);
	
	/*!
	 * \brief Partial pivoting method
	 * \param the row to pivot
	 * \return The index of the pivot element
	 */
	IMPORT_C TInt Pivot(int row);

	/*!
	 * \brief Getter for the matrix table
	 * \return The CFixed** iMatrix variable
	 */
	IMPORT_C CFixed** Matrix();
protected:

	//Column and Row sizes
	TInt iCols,iRows;
	//The actual data
	CFixed** iMatrix;

	};
	
#endif
